/**
 * The MIT License (MIT)
 * Copyright © 2021 Walkline Wang (https://walkline.wang)
 * https://gitee.com/walkline/online-update-manager
 */	

'use strict'

$(function () {
	app.initialize()
})

var app = {
	controls: {
		text_package_name: $('#text_package_name'),
		text_app_version: $('#text_app_version'),
		text_test_app_version: $('#text_test_app_version'),
		text_selected_row_index: $('#text_selected_row_index'),
		textarea_app_note: $('#textarea_app_note'),
	
		button_append_package: $('#button_append_package'),
		button_remove_package: $('#button_remove_package'),
		button_save_app_information: $('#button_save_app_information'),
		button_test_package_last: $('#button_test_package_last'),
		button_test_package_specified: $('#button_test_package_specified'),
		button_logout: $('#button_logout'),
		button_remove_record_item: $('#button_remove_record_item'),
		button_remove_record_and_file: $('#button_remove_record_and_file'),

		select_remove_package: $('#select_remove_package'),
		select_manage_package: $('#select_manage_package'),
		select_history_package: $('#select_history_package'),
		select_test_package: $('#select_test_package'),

		radio_option_apk: $('#radio_option_apk'),
		radio_option_wgt: $('#radio_option_wgt'),

		radio_option_apk_label: $('#radio_option_apk_label'),
		radio_option_wgt_label: $('#radio_option_wgt_label'),

		checkbox_force_update: $('#checkbox_force_update'),

		input_app_file: $('#input_app_file'),
		input_app_file_label: $('#input_app_file_label'),

		progress_upload_progress: $('#progress_upload_progress'),

		datatable: $('#datatable'),

		modal_row_detail: $('#modal_row_detail'),
		modal_row_detail_title: $('#modal_row_detail_title'),
		modal_row_detail_version: $('#modal_row_detail_version'),
		modal_row_detail_name: $('#modal_row_detail_name'),
		modal_row_detail_size: $('#modal_row_detail_size'),
		modal_row_detail_type: $('#modal_row_detail_type'),
		modal_row_detail_date: $('#modal_row_detail_date'),
		modal_row_detail_force: $('#modal_row_detail_force')
	},

	datatable: {},
	uploader: {},


	initialize: function () {
		this._bind_append_package_click_event()
		this._bind_remove_package_click_event()
		this._bind_input_app_file_change_event()
		this._bind_history_package_change_event()
		this._bind_save_app_information_click_event2()
		// this._bind_save_app_information_click_event()
		this._bind_test_package_click_event()
		this._bind_logout_click_event()
		this._bind_datatable_tr_click_event()
		this._bind_remove_record_item_and_file_click_event()
		this._bind_remove_record_item_click_event()

		this._init_toastr()
		this._init_datatable()
		this._init_uploader()

		this._reload_data()
	},

	_init_datatable: function () {
		app.datatable = this.controls.datatable.DataTable({
			lengthChange: false,
			searching: false,
			ordering: false,
			info: false,
			autoWidth: true,
			responsive: true,
			pageLength: 15,
			scrollX: true,
			scrollY: 375,
			pagingType: 'simple_numbers',
			scrollCollapse: true,
			language: {
				paginate: {
					first: '首页',
					previous: '上一页',
					next: '下一页',
					last: '尾页'
				},
				sLoadingRecords: '努力读取中...',
				sEmptyTable: '没找到符合条件的数据',
				sZeroRecords: '没有匹配结果'
			},
			serverSide: false,
			ajax: {
				url: CONST.UPDATE_API_URI + CONST.COMMANDS.LOAD_APPS,
				type: "POST",
				data: (data) => {
					data = {
						package_name: app.controls.select_history_package.get(0).selectedIndex > 0 ? app.controls.select_history_package.get(0).value : ''
					}

					return data
				},
				// dataSrc: 'apps'
				dataSrc: (result) => {
					if (!result.error_code) {
						return result.apps
					} else {
						if (result.error_code === 1002) {
							location.reload()
						} else {
							toastr.error(result.error_msg)
							return []
						}
					}
				}
			},
			columns: [
				{
					'data': (item) => {
						return `<span class="badge badge-secondary">${item.version}</span>`
					},
					'className': 'center'
				},
				{'data': 'filename', 'className': 'center'},
				{
					'data': (item) => {
						return this._bytes_to_size(item.size)
					},
					'className': 'center'
				},
				{
					'data': (item) => {
						const type = item.is_apk ? 'apk' : (item.is_wgt ? 'wgt' : ''),
							theme = item.is_apk ? 'success' : (item.is_wgt ? 'danger' : 'primary')
						return `<span class="badge badge-${theme}">${type}</span>`
					},
					'className': 'center'
				},
				// {
				// 	'data': (item) => {
				// 		const checked = item.is_apk ? 'checked' : ''
				// 		return `<div class="custom-control custom-radio"><input type="radio" class="custom-control-input" ${checked} disabled><label class="custom-control-label" /></div>`
				// 	},
				// 	'className': 'center'
				// },
				// {
				// 	'data': (item) => {
				// 		const checked = item.is_wgt ? 'checked' : ''
				// 		return `<div class="custom-control custom-radio"><input type="radio" class="custom-control-input" ${checked} disabled><label class="custom-control-label" /></div>`
				// 	},
				// 	'className': 'center'
				// },
				{
					'data': (item) => {
						const checked = item.is_force_update ? 'checked' : ''
						return `<div class="custom-control custom-checkbox"><input type="checkbox" class="custom-control-input" ${checked} disabled><label class="custom-control-label" /></div>`
					},
					'className': 'center'
				},
				{'data': 'date', 'className': 'center'}
			]
		})
	},

	_init_uploader: function () {
		app.uploader = new fcup({
			url: CONST.UPDATE_API_URI + CONST.COMMANDS.UPLOAD_APP_APART,
			type: "apk,wgt,wtgu", // 限制上传类型，为空不限制
			shardsize: "1", // 每次分片大小，单位为M，默认1M
			minsize: '0.1', // 最小文件上传M数，单位为M，默认为无
			maxsize: "20", // 上传文件最大M数，单位为M，默认200M
			append_data: {}, //每次上传的附加数据
			
			// 错误提示
			error: (msg) => {
				toastr.error(msg)
			},

			// 等待上传事件，可以用来loading
			beforeSend: () => {},
	
			// 上传进度事件
			progress: (num, other) => {
				this._set_progress_value(num)

				// console.log(num + '%')
				// console.log('上传进度' + num)
				// console.log("上传类型" + other.type)
				// console.log("已经上传" + other.current)
				// console.log("剩余上传" + other.surplus)
				// console.log("已用时间" + other.usetime)
				// console.log("预计时间" + other.totaltime)
			},
			
			upload_success: () => {},

			// 上传成功回调，回调会根据切片循环，要终止上传循环，必须要return false，成功的情况下要始终返回true
			success: function (res) {
				let data = res ? eval('(' + res + ')') : ''

				if (data.status == 2) {
					if (this.upload_success) {this.upload_success()}
				}

				return true
			}
		})
	},

	_init_toastr: function () {
		toastr.options.positionClass = 'toast-top-right'
		toastr.options.timeOut = 3000
	},


	/********************
	 * 触发类事件绑定函数 *
	 ********************/

	// 绑定 用户退出 按钮点击事件
	_bind_logout_click_event: function () {
		this.controls.button_logout.on('click', () => {
			$.post(CONST.UPDATE_API_URI + CONST.COMMANDS.LOGOUT_USER, {}, () =>{
				location.reload()
			})
		})
	},

	// 绑定 模态框 中 删除记录和文件 按钮点击事件
	_bind_remove_record_item_and_file_click_event: function () {
		this.controls.button_remove_record_and_file.on('click', () => {
			if (confirm('是否删除记录和文件？')) {
				this._remove_record(1)
			}
		})
	},

	// 绑定 模态框 中 删除记录 按钮点击事件
	_bind_remove_record_item_click_event: function () {
		this.controls.button_remove_record_item.on('click', () => {
			if (confirm('是否删除记录？')) {
				this._remove_record()
			}
		})
	},

	// 绑定 历史版本 页面中 DataTable 行点击事件
	_bind_datatable_tr_click_event: function () {
		this.controls.datatable.on('click', 'tr', function () {
			const row = app.datatable.row(this),
				row_data = row.data()

			if (row_data === undefined) {return}

			let ctrls = app.controls

			// ctrls.modal_row_detail_title.html(row.filename)
			ctrls.modal_row_detail_version.val(row_data.version)
			ctrls.modal_row_detail_name.val(row_data.filename)
			ctrls.modal_row_detail_size.val(app._bytes_to_size(row_data.size))
			ctrls.modal_row_detail_type.val(row_data.is_apk ? 'apk' : (row_data.is_wgt ? 'wgt' : ''))
			ctrls.modal_row_detail_date.val(row_data.date)
			ctrls.modal_row_detail_force.val(row_data.is_force_update ? 'True' : 'False')
			ctrls.text_selected_row_index.val(row.index())

			ctrls.modal_row_detail.modal('show')
		})
	},

	// 绑定 版本管理 页面中 保存 按钮点击事件
	_bind_save_app_information_click_event2: function () {
		const ctrls = this.controls

		ctrls.button_save_app_information.on('click', () => {
			if (!this._validate_upload_app_information_value()) {
				toastr.warning('请填写全部信息')
				return
			}

			if (this._check_upload_file()) {
				const input_app_file = ctrls.input_app_file,
					package_name = ctrls.select_manage_package.val(),
					is_apk = ctrls.radio_option_apk.prop('checked'),
					is_wgt = ctrls.radio_option_wgt.prop('checked'),
					is_force_update = ctrls.checkbox_force_update.prop('checked'),
					sub_folder = is_apk ? 'apk' : (is_wgt ? 'wgt' : ''),
					input_app_file_label = ctrls.input_app_file_label,
					text_app_version = ctrls.text_app_version,
					textarea_app_note = ctrls.textarea_app_note

				app.uploader.append_data = {
					package_name: package_name,
					sub_folder: sub_folder,
					app_version: text_app_version.val(),
					app_note: textarea_app_note.val(),
					is_apk: is_apk,
					is_wgt: is_wgt,
					is_force_update: is_force_update
				}

				app.uploader.upload_success = () => {
					toastr.success('记录添加成功')

					input_app_file.val('')
					input_app_file_label.prop('innerText', '')
					text_app_version.val('')
					textarea_app_note.val('')
					this._reload_data()
					this._set_progress_value(0)
				}
				app.uploader.upload(input_app_file.prop('files')[0])
			}
		})
	},

	// (已弃用)绑定 版本管理 页面中 保存 按钮点击事件
	_bind_save_app_information_click_event: function () {
		this.controls.button_save_app_information.on('click', () => {
			if (!this._validate_upload_app_information_value()) {
				toastr.warning('请填写全部信息')
				return
			}

			const ctrls = this.controls,
				input_app_file = ctrls.input_app_file,
				input_app_file_label = ctrls.input_app_file_label,
				select_manage_package = ctrls.select_manage_package,
				text_app_version = ctrls.text_app_version,
				textarea_app_note = ctrls.textarea_app_note,
				radio_option_apk = ctrls.radio_option_apk,
				radio_option_wgt = ctrls.radio_option_wgt,
				checkbox_force_update = ctrls.checkbox_force_update,
				params = {
					package_name: select_manage_package.val(),
					app_version: text_app_version.val(),
					app_note: textarea_app_note.val(),
					is_apk: radio_option_apk.prop('checked'),
					is_wgt: radio_option_wgt.prop('checked'),
					is_force_update: checkbox_force_update.prop('checked')
				}

			let data = new FormData()
			data.append(CONST.UPLOAD_FILENAME, input_app_file.prop('files')[0])
			data.append('params', JSON.stringify(params))

			$.ajax({
				type: 'POST',
				url: CONST.UPDATE_API_URI + CONST.COMMANDS.UPLOAD_APP,
				data: data,
				cache: false,
				processData: false,
				contentType: false,
				success: (result) => {
					if (!result.error_code) {
						toastr.success('记录添加成功')

						input_app_file.val('')
						input_app_file_label.prop('innerText', '')
						text_app_version.val('')
						textarea_app_note.val('')
						this._reload_data()
					} else {
						if (result.error_code === 1002) {
							location.reload()
						} else {
							toastr.warning('错误: ' + result.error_msg)
						}
					}
				}
			})
		})
	},

	// 绑定 版本管理 页面中 文件组件 变更事件
	_bind_input_app_file_change_event: function () {
		this.controls.input_app_file.on('change', (event) => {
			const ctrls = this.controls,
				files = event.target.files,
				radio_option_apk = ctrls.radio_option_apk,
				radio_option_wgt = ctrls.radio_option_wgt,
				radio_option_apk_label = ctrls.radio_option_apk_label,
				radio_option_wgt_label = ctrls.radio_option_wgt_label

			if (files.length > 0) {
				const filename = files[0].name
				let extention = filename.split('.')

				if (extention.length > 1) {
					extention = extention[extention.length -1].toLowerCase()

					if (extention === 'apk') {
						radio_option_apk.prop('checked', true)
						radio_option_apk_label.addClass('active')
						radio_option_wgt_label.removeClass('active')
					} else if (extention === 'wgt' || extention === 'wgtu') {
						radio_option_wgt.prop('checked', true)
						radio_option_wgt_label.addClass('active')
						radio_option_apk_label.removeClass('active')
					} else {
						toastr.warning('警告: 选中的可能不是 app 文件')
					}
				}
			}
		})
	},

	// 绑定 接口测试 页面中 测试 按钮点击事件
	_bind_test_package_click_event: function () {
		$('#button_test_package_last, #button_test_package_specified').on('click', (event) => {
			console.log(event.target.id)

			if (!this._validate_test_api_information_value()) {
				toastr.warning('请填写全部信息')
				return
			}

			const ctrls = this.controls,
				select_test_package = ctrls.select_test_package,
				text_test_app_version = ctrls.text_test_app_version

			output.clear()
			output.append(`url: '${CONST.UPDATE_API_URI + CONST.COMMANDS.CHECK_UPDATE}'`)
			output.append(`method: 'POST'`)
			output.append(`data: {\n\tpackage_name: '${select_test_package.val()}',\n\tapp_version: '${text_test_app_version.val()}'\n}`)
			output.append('\nresult: {')

			$.post(CONST.UPDATE_API_URI + CONST.COMMANDS.CHECK_UPDATE, {
				package_name: select_test_package.val(),
				app_version: text_test_app_version.val(),
				get_last_version: event.target.id === 'button_test_package_last' ? true : false
			}, (result) => {
				if (!result.error_code) {
					text_test_app_version.val('')
					this._reload_data()

					output.append(`\tstatus: ${result.status} // 0: 无更新, 1: apk 更新, 2: wgt 更新`)

					if (result.status > 0) {
						output.append(`\tversion: '${result.version}'`)
						output.append(`\tnote: \n'${result.note}'`)
						output.append(`\tsize: ${result.size}`)
						output.append(`\turl: '${result.url}'`)
						output.append(`\tforce_update: ${result.force_update}`)
						output.append(`\tdate: '${result.date}'`)
					}
				} else {
					output.append(`\terror_code: ${result.error_code}\n\terror_msg: '${result.error_msg}'`)
					toastr.warning('错误: ' + result.error_msg)
				}

				output.append('}')
			})
		})
	},

	// 绑定 APP 管理 页面中 添加 按钮点击事件
	_bind_append_package_click_event: function () {
		this.controls.button_append_package.on('click', () => {
			if (this._validate_package_name_value()) {
				$.post(CONST.UPDATE_API_URI + CONST.COMMANDS.APPEND_PACKAGE, {
					package_name: app.controls.text_package_name.val()
				}, (result) => {
					if (!result.error_code) {
						toastr.success('记录添加成功')

						this.controls.text_package_name.val('')
						this._reload_data()
					} else {
						if (result.error_code === 1002) {
							location.reload()
						} else {
							toastr.warning('错误: ' + result.error_msg)
						}
					}
				})
			}
		})
	},

	// 绑定 APP 管理 页面中 删除 按钮点击事件
	_bind_remove_package_click_event: function () {
		this.controls.button_remove_package.on('click', () => {
			if (this._validate_selected_remove_package_value()) {
				$.post(CONST.UPDATE_API_URI + CONST.COMMANDS.REMOVE_PACKAGE, {
					package_name: app.controls.select_remove_package.val()
				}, (result) => {
					if (!result.error_code) {
						this._reload_data()
					} else {
						if (result.error_code === 1002) {
							location.reload()
						} else {
							toastr.warning('错误: ' + result.error_msg)
						}
					}
				})
			}
		})
	},

	// 绑定 历史版本 页面中 下拉框 变更事件
	_bind_history_package_change_event: function () {
		this.controls.select_history_package.on('change', (event) => {
			// event.target.selectedIndex > 0
			if (this._validate_selected_history_package_value()) {
				app.datatable.ajax.reload()
			} else {
				app.datatable.clear().draw()
			}
		})
	},


	/*****************
	 * 参数验证类函数 *
	 *****************/

	// 验证 APP 管理页面中 文本框 内容
	_validate_package_name_value: function () {
		let result = true
		const package_name = this.controls.text_package_name

		if (package_name.val().trim() === '') {
			toastr.warning('包名不能为空')

			package_name.focus()
			result = false
		}

		return result
	},

	// 验证 历史版本 页面中 下拉框 内容
	_validate_selected_history_package_value: function () {
		return this.controls.select_history_package.get(0).selectedIndex > 0 ? true : false
	},

	// 验证 APP 管理 页面中 下拉框 内容
	_validate_selected_remove_package_value: function () {
		return this.controls.select_remove_package.get(0).selectedIndex > 0 ? true : false
	},

	// 验证 接口测试 页面中 下拉框、文本框 内容
	_validate_test_api_information_value: function () {
		let result = true
		const ctrls = this.controls,
			select_test_package = ctrls.select_test_package,
			text_test_app_version = ctrls.text_test_app_version
		
		result &= select_test_package.get(0).selectedIndex > 0
		result &= text_test_app_version.val().trim().length > 0

		return result
	},

	// 验证 版本管理 页面中所有内容
	_validate_upload_app_information_value: function () {
		let result = true
		const ctrls = this.controls,
			files = ctrls.input_app_file.prop('files'),
			select_manage_package = ctrls.select_manage_package,
			text_app_version = ctrls.text_app_version,
			textarea_app_note = ctrls.textarea_app_note
		
		result &= files.length > 0
		result &= select_manage_package.get(0).selectedIndex > 0
		result &= text_app_version.val().trim().length > 0
		result &= textarea_app_note.val().trim().length > 0

		return result
	},


	/*****************
	 * 功能辅助类函数 *
	 *****************/

	/**
	 * 检查 版本管理 页面中待上传文件是否已经上传过
	 * 
	 * 根据数据库中的记录：
	 *   1. 如果记录不存在，则不管文件是否存在都继续上传
	 *   2. 如果记录存在且文件存在，则停止上传
	 */
	_check_upload_file: function () {
		let result = false
		const ctrls = this.controls,
			filename = ctrls.input_app_file.prop('files')[0].name,
			package_name = ctrls.select_manage_package.val(),
			is_apk = ctrls.radio_option_apk.prop('checked'),
			is_wgt = ctrls.radio_option_wgt.prop('checked'),
			sub_folder = is_apk ? 'apk' : (is_wgt ? 'wgt' : '')

		if (sub_folder === '') {
			toastr.warning('错误: 只能上传安卓资源文件')
		} else {
			$.ajaxSettings.async = false
			$.post(CONST.UPDATE_API_URI + CONST.COMMANDS.CHECK_UPLOAD_FILE, {
				package_name: package_name,
				filename: filename,
				sub_folder: sub_folder
			}, (res) => {
				if (!res.error_code) {
					result = true
				} else {
					toastr.warning('错误: ' + res.error_msg)
				}
			})
			$.ajaxSettings.async = true
		}

		return result
	},

	// 重新加载所有页面中 下拉框 的选项内容，并刷新 历史版本 中 DataTable 的数据
	_reload_data: function () {
		$.post(CONST.UPDATE_API_URI + CONST.COMMANDS.LOAD_PACKAGES, {}, (result) => {
			if (!result.error_code) {
				const ctrls = this.controls,
					select_remove_package = ctrls.select_remove_package,
					select_manage_package = ctrls.select_manage_package,
					select_history_package = ctrls.select_history_package,
					select_test_package = ctrls.select_test_package,
					first_option = `<option selected>Select a package...</option>`

				select_remove_package.empty()
				select_manage_package.empty()
				select_history_package.empty()
				select_test_package.empty()
				select_remove_package.append(first_option)
				select_manage_package.append(first_option)
				select_history_package.append(first_option)
				select_test_package.append(first_option)

				$.each(result.packages, function (index, item) {
					const other_option = `<option value='${item}'>${item}</option>`

					select_remove_package.append(other_option)
					select_manage_package.append(other_option)
					select_history_package.append(other_option)
					select_test_package.append(other_option)
				})

				app.datatable.ajax.reload()
			} else if (result.error_code === 1002) {
				location.reload()
			}
		})
	},

	// 文件大小可读性转换函数
	_bytes_to_size: function (bytes) {
		if (bytes === 0) return '0 B'
		const k = 1024,
			sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
			i = Math.floor(Math.log(bytes) / Math.log(k))

	   return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i]
	},

	// 设置 版本管理 页面中 进度条 当前值
	_set_progress_value: function (value) {
		this.controls.progress_upload_progress.css('width', `${value}%`)
	},

	// 删除 历史版本 中已存在的记录和文件
	_remove_record: function (include_file=0) {
		const ctrls = this.controls,
			selected_row_index = parseInt(ctrls.text_selected_row_index.val()),
			row_data = app.datatable.row(selected_row_index).data(),
			package_name = ctrls.select_history_package.val()

		$.post(CONST.UPDATE_API_URI + CONST.COMMANDS.REMOVE_APP, {
			package_name: package_name,
			include_file: include_file,
			row_data: row_data
		}, (result) => {
			if (!result.error_code) {
				app.datatable.row(selected_row_index).remove().draw()
				toastr.success(result.result_msg)
			} else {
				if (result.error_code === 1002) {
					location.reload()
				} else {
					toastr.error('错误: ' + result.error_msg)
				}
			}
		})

		ctrls.modal_row_detail.modal('hide')
	}
}


/*******************
 * 输出文字显示组件 *
 *******************/
var output = {
	output_box: $('#output_test_result'),

	append: function (msg) {
		const output = this.output_box

		msg = msg.replace(/\n/g, '<br/>').replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;')

		if (output.hasClass('d-none')) {output.removeClass('d-none')}

		output.append(`<samp><p class="mb-0 text-nowrap">${msg}</p></samp>`)
		output.animate({
			scrollTop: output.prop('scrollHeight')
		}, 100)
	},

	clear: function () {
		this.output_box.prop('innerHTML', '')
		this.output_box.addClass('d-none')
	}
}
